#include "../include/debugger.h"

extern qword iregs[128];
extern real4 fregs[32];
extern real8 dregs[32];
extern VREG vregs[64];

extern std::fstream disk;
extern Table gdt[4096];
extern byte ram[MAX_MEM];

inline void add_break(qword address)
{
	breakpoints.push_back(address);
}
inline void remove_break(qword address)
{
	for (int i = 0; i < breakpoints.size(); i++)
	{
		if (breakpoints[i] == address)
		{
			breakpoints.erase(breakpoints.begin() + i);
			return;
		}
	}
}
inline void printbrk()
{
	for (int i = 0; i < breakpoints.size(); i++)
	{
		printf("Break Point %x : 0x%llx\n", i, breakpoints[i]);
	}
}
void print(int argc, char **argv)
{
	std::string type, arg;
	if (argc <= 0)
		std::cin >> type >> arg;
	else if (argc == 1)
		std::cin >> arg;
	else
	{
		type = argv[0];
		arg = argv[1];
	}
	qword value = std::strtoull(arg.c_str(), NULL, 16);
	if (type == "help")
		std::cout << "View the register and ram data:\n"
				  << "\'ram\':Receive an address,check the 128 bytes block ram.\n"
				  << "\'Ireg\':Receive an register label,check the int register value.\n"
				  << "\'Freg\':Receive an register label,check the float register value."
				  << "\'Dreg\':Receive an register label,check the double register value.\n"
				  << "\'Vreg\':Receive an register label,check the vector register value.\n"
				  << "\'gdt\':Receive an sector target,check the sector data.\n"
				  << std::endl;
	else if (type == "ram")
	{
		qword base = value & 0xffffffffffffff80;
		for (int i = 0; i < 128; i++)
		{
			if ((base + i) % 16 == 0)
				printf("0x%016llx:", base + i);
			printf("0x%02x ", ram[base + i]);
			if ((base + i) % 16 == 7)
				printf(" ");
			else if ((base + i) % 16 == 15)
				printf("\n");
		}
	}
	else if (type == "Ireg")
		printf("Int Reg 0x%02llx:0x%016llx\n", value & 0x7f, iregs[value & 0x7f]);
	else if (type == "Freg")
		printf("Float Reg 0x%02llx:%f\n", value & 0x1f, fregs[value & 0x1f]);
	else if (type == "Dreg")
		printf("Double Reg 0x%02llx:%lf\n", value & 0x1f, dregs[value & 0x1f]);
	else if (type == "Vreg")
	{
		printf("Vector Reg 0x%02llx:", value & 0x3f);
		for (int i = 0; i < 64; i++)
		{
			printf("0x%02x ", vregs[value & 0x3f].bvalues[i]);
		}
		printf("\n");
	}
	else if (type == "gdt")
		printf("Sector Table 0x%04llx:Base Address:0x%016llx,Length:0x%016llx,Description:0x%02x\n", value & 0xfff, gdt[value].base, gdt[value].length, gdt[value].descript);
	printf("\n");
}
inline void step()
{
	selector(loader());
}
inline void execute()
{
	while ((iregs[Flag] & (RUNNING + ERROR)) && !(iregs[Flag] & DEBUG))
		selector(loader());
}
void bdebug()
{
	while (iregs[Flag] & (RUNNING + ERROR))
	{
		selector(loader());
		if (std::find(breakpoints.begin(), breakpoints.end(), iregs[Code]) != breakpoints.end())
		{
			iregs[Flag] |= DEBUG;
			return;
		}
	}
}
void debug_main(int argc, char **argv)
{
	std::cin.ignore(0xffff, '\n');
	std::string option, value;
	if (argc == 0)
		std::cin >> option >> value;
	else
		option = argv[0];
	if (option == "help")
		std::cout << "Debugger system:\n"
		<< "\'addbrk\':Receive an address,set to the breakpoint.\n"
		<< "\'removebrk\':Receive an address,remove this breakpoint.\n"
		<< "\'step\':Debug step by step.\n"
		<< "\'bdeubg\':Execute to the program until the breakpoint.\n"
		<< "\'execute\':Execute the program until the end.\n"
		<< "\'print\':Receive option and value,check the data.\n"
		<< "\'printbrk\':Print all breakpoints.\n"
		<< std::endl;
	else if (option == "addbrk")
	{
		if (argc > 1)
			value = argv[1];
		add_break(std::strtoull(value.c_str(), NULL, 16));
	}
	else if (option == "removebrk")
	{
		if (argc > 1)
			value = argv[1];
		remove_break(std::strtoull(value.c_str(), NULL, 16));
	}
	else if (option == "step")
		step();
	else if (option == "execute")
		execute();
	else if (option == "bdebug")
		bdebug();
	else if (option == "print")
		print(argc - 1, argv + 1);
	else if (option == "printbrk")
		printbrk();
	else if ((option == "exit") || (option == "quit"))
		exit(0);
	else
		std::cout << "Invalid Option!\n";
}